#pragma once
#include <vector>
#include <memory>

class CommFilter {
public:
    virtual ~CommFilter() = default;
    virtual std::vector<uint8_t> processTx(const std::vector<uint8_t>& data) = 0;
    virtual std::vector<uint8_t> processRx(const std::vector<uint8_t>& data) = 0;
};

class FilterChain {
public:
    void addFilter(std::shared_ptr<CommFilter> filter) {
        filters_.push_back(filter);
    }

    std::vector<uint8_t> applyTxFilters(const std::vector<uint8_t>& data) {
        auto processed = data;
        for (auto& filter : filters_) {
            processed = filter->processTx(processed);
        }
        return processed;
    }

    std::vector<uint8_t> applyRxFilters(const std::vector<uint8_t>& data) {
        auto processed = data;
        for (auto it = filters_.rbegin(); it != filters_.rend(); ++it) {
            processed = (*it)->processRx(processed);
        }
        return processed;
    }

private:
    std::vector<std::shared_ptr<CommFilter>> filters_;
};

class CrcFilter : public CommFilter {
public:
    std::vector<uint8_t> processTx(const std::vector<uint8_t>& data) override {
        auto crc = calculateCrc(data);
        auto result = data;
        result.push_back(static_cast<uint8_t>(crc >> 8));
        result.push_back(static_cast<uint8_t>(crc & 0xFF));
        return result;
    }

    std::vector<uint8_t> processRx(const std::vector<uint8_t>& data) override {
        if (data.size() < 2) return {};
        
        uint16_t receivedCrc = (data[data.size()-2] << 8) | data.back();
        auto calculatedCrc = calculateCrc({data.begin(), data.end()-2});
        
        if (receivedCrc != calculatedCrc) return {};
        return {data.begin(), data.end()-2};
    }

private:
    uint16_t calculateCrc(const std::vector<uint8_t>& data) {
        // CRC16-CCITT实现
        uint16_t crc = 0xFFFF;
        for (uint8_t b : data) {
            crc ^= (uint16_t(b) << 8);
            for (int i = 0; i < 8; ++i) {
                if (crc & 0x8000) {
                    crc = (crc << 1) ^ 0x1021;
                } else {
                    crc <<= 1;
                }
            }
        }
        return crc;
    }
};